home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Modules
/
BackSpaceModules
/
Source
/
SchoolView
/
Thinker.m
< prev
Wrap
Text File
|
1994-04-16
|
19KB
|
884 lines
// Thinker.m
//
// This class is the brains behind the BackSpace app; it is the Application
// object's delegate, and it watches the system to determine when to
// initiate the screen saver mode.
//
// You may freely copy, distribute, and reuse the code in this example.
// NeXT disclaims any warranty of any kind, expressed or implied, as to its
// fitness for any particular use.
#import "Thinker.h"
#import "BackWindow.h"
#import "BackView.h"
#import "SpaceView.h"
#import "MySlider.h"
#import "Password.h"
#import "psfuncts.h"
#import <appkit/appkit.h>
#import <objc/NXBundle.h>
// convert vertical blank time to milliseconds
#define SEC2MS(x) ((x * 1000) + 20)
//#define SHOWITERATIONSPERSEC
#ifdef SHOWITERATIONSPERSEC
unsigned iterations;
BStimeval then, now, targetTime;
#endif
static id _BSThinker;
id BSThinker()
{ return _BSThinker;
}
@implementation Thinker
- appDidInit:sender
{
const char *autoLaunch;
globalTier = BACKGROUNDTIER;
openAnother = YES;
_BSThinker = self;
backZone = NXCreateZone(vm_page_size, vm_page_size, YES);
NXSetRect(&windowRect, 475, 300, 500, 450);
[NXApp getScreens:&screens count:&screenCount];
[commonImageInspector getFrame: &inspectorFrame];
currentInspector = commonImageInspector;
[self getViewType];
[self setVirtualViewIndexAndIncrement:NO];
[self getWindowType];
[self getScreenSaverSetting];
[self getScreenLockerSetting];
[self getPrioritySetting];
[self getImageFile];
[self getHotCornerSetting];
autoLaunch = NXGetDefaultValue([NXApp appName], "NXAutoLaunch");
if (strcmp(autoLaunch,"YES"))
{
[[windMatrix window] makeKeyAndOrderFront:self];
windowHasBeenDisplayed = YES;
}
else [NXApp hide:self];
#ifdef SHOWITERATIONSPERSEC
then = currentTimeInMs();
targetTime = then + 10000;
#endif
srandom(time(0));
return self;
}
- appDidHide:sender
{
if (windowType != BACKWINDOW) [self removeTimer];
return self;
}
- appDidUnhide:sender
{
if (!windowHasBeenDisplayed)
{
[[windMatrix window] makeKeyAndOrderFront:self];
windowHasBeenDisplayed = YES;
}
if (windowType != NOWINDOW) [self createTimer];
return self;
}
// Pretty much a dummy function to invoke the step method.
void timedEntryFunction (DPSTimedEntry timedEntry, double timeNow, void *theObject)
{ [(id)theObject doDistributorLoop];
}
- createTimer
{
if (!timerValid)
{
timerValid = YES;
timer = DPSAddTimedEntry(0.02, &timedEntryFunction, self, NX_BASETHRESHOLD);
}
return self;
}
- removeTimer
{
if (timerValid) DPSRemoveTimedEntry (timer);
timerValid = NO;
return self;
}
- doDistributorLoop
{
NXEvent dummyEvent;
keepLooping = YES;
[spaceView lockFocus];
if ([spaceView respondsTo:@selector(didLockFocus)]) [spaceView didLockFocus];
do {
[spaceView oneStep];
[spaceWindow flushWindow];
NXPing (); // Synchronize postscript for smoother animation
[spaceView oneStep];
[spaceWindow flushWindow];
NXPing (); // Synchronize postscript for smoother animation
#ifdef SHOWITERATIONSPERSEC
iterations++;
if ((now = currentTimeInMs()) > targetTime)
{
printf("BackSpace: %5.1f its/sec\n",
(double)iterations*1000.0/(double)(now - then));
iterations = 0;
targetTime = now + 10000;
then = now;
}
#endif
} while (timerValid && keepLooping &&
([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent
waitFor:0 threshold:NX_BASETHRESHOLD] == NULL));
[spaceView unlockFocus];
return self;
}
- installSpaceViewIntoWindow:w
{
NXRect cvrect;
int i;
id subviews, contentView;
if (!w) return nil;
contentView = [w contentView];
// get size of content view
[contentView getBounds:&cvrect];
// remove old subviews, this is overkill really...
subviews = [contentView subviews];
for (i=([subviews count]-1); i>=0; i--)
{ [[subviews objectAt:i] removeFromSuperview];
}
// install it into the window's content view
[contentView addSubview:spaceView];
[contentView setAutoresizeSubviews:YES];
[spaceView setAutosizing:NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE];
// size the spaceview
[spaceView sizeTo:cvrect.size.width :cvrect.size.height];
return self;
}
- useNormalWindow
{
int myBacking;
spaceView = [self backView];
myBacking = [self backingTypeForView:spaceView];
if (!normalWindow)
{
normalWindow = [[Window allocFromZone:backZone]
initContent:&windowRect style:NX_RESIZEBARSTYLE
backing:myBacking
buttonMask:NX_CLOSEBUTTONMASK
defer:NO];
[self setWindowTitle];
[normalWindow useOptimizedDrawing:YES];
[normalWindow setDynamicDepthLimit:YES]; //want window depth to match device!
[normalWindow setOneShot:YES];
[normalWindow setDelegate:self];
[normalWindow setBackgroundGray:NX_BLACK];
}
spaceWindow = normalWindow;
[self installSpaceViewIntoWindow:spaceWindow];
if ([spaceView respondsTo:@selector(setImage:)])
[spaceView setImage: image];
if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
[spaceWindow display];
[spaceWindow makeKeyAndOrderFront:self];
// need to do this so flushing always works!
// must do it late because kit does lazy window creation ie the PostScript
// window might not exist until you actually draw to it
if (myBacking == NX_RETAINED)
[spaceWindow setBackingType:NX_RETAINED];
else [spaceWindow setBackingType:NX_BUFFERED];
return self;
}
- (int) backingTypeForView:aView
{
if ([aView respondsTo:@selector(useBufferedWindow)]
&& [aView useBufferedWindow])
return NX_BUFFERED;
return NX_RETAINED;
}
- useBackWindow:(int)tier
{
NXRect r={{0, 0}};
int myBacking;
[NXApp getScreenSize:&(r.size)];
spaceView = [self backView];
myBacking = [self backingTypeForView:spaceView];
[self createBigWindowIfNecessaryForView:spaceView];
if (myBacking == NX_RETAINED)
{ spaceWindow = bigUnbufferedWindow;
tweakWindow([spaceWindow windowNum], tier);
}
else
{ spaceWindow = bigBufferedWindow;
}
[self installSpaceViewIntoWindow:spaceWindow];
if ([spaceView respondsTo:@selector(setImage:)])
[spaceView setImage: image];
[spaceWindow placeWindow:&r];
if (myBacking == NX_BUFFERED) [spaceWindow display];
[spaceWindow orderFront:self];
if (myBacking == NX_BUFFERED) tweakWindow([spaceWindow windowNum], tier);
else [spaceWindow display];
if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
return self;
}
- createBigWindowIfNecessaryForView:aView
{
NXRect r={{0, 0}};
int myBacking = [self backingTypeForView:aView];
[NXApp getScreenSize:&(r.size)];
if ((myBacking == NX_RETAINED) && !bigUnbufferedWindow)
{
bigUnbufferedWindow = [[BackWindow allocFromZone:backZone]
initContent:&r style:NX_TOKENSTYLE
backing:NX_NONRETAINED buttonMask:0 defer:NO];
[bigUnbufferedWindow useOptimizedDrawing:YES];
[bigUnbufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK
| NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
| NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
| NX_CURSORUPDATEMASK)];
[bigUnbufferedWindow addToEventMask:NX_FLAGSCHANGEDMASK];
[bigUnbufferedWindow setBackgroundGray:NX_BLACK];
}
if ((myBacking == NX_BUFFERED) && !bigBufferedWindow)
{
bigBufferedWindow = [[BackWindow allocFromZone:backZone]
initContent:&r style:NX_TOKENSTYLE
backing:NX_BUFFERED buttonMask:0 defer:NO];
[bigBufferedWindow useOptimizedDrawing:YES];
[bigBufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK
| NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
| NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
| NX_CURSORUPDATEMASK)];
[bigBufferedWindow addToEventMask:NX_FLAGSCHANGEDMASK];
[bigBufferedWindow setDynamicDepthLimit:YES]; //want window depth to match device!
[bigBufferedWindow setOneShot:YES];
[bigBufferedWindow setBackgroundGray:NX_BLACK];
}
return self;
}
- changeWindowType:sender
{
[self changeWindowTypeAndRemember:YES];
return self;
}
- changeWindowTypeAndRemember:(BOOL)rem
{
char str[10];
int newWindowType;
newWindowType = [windMatrix selectedRow];
if (newWindowType == windowType) return self;
windowType = newWindowType;
if (rem)
{
sprintf(str,"%1d", windowType);
NXWriteDefault([NXApp appName], "windowType", str);
}
[spaceWindow orderOut:self];
switch (windowType)
{
case NOWINDOW:
[self removeTimer];
break;
case NORMALWINDOW:
[self useNormalWindow];
[self createTimer];
break;
case BACKWINDOW:
[self useBackWindow: globalTier];
[self createTimer];
break;
}
return self;
}
- getWindowType
{
int tWindowType = NORMALWINDOW;
const char *ptr;
int val;
ptr = NXGetDefaultValue([NXApp appName], "windowType");
if (ptr)
{
sscanf(ptr,"%d",&val);
if (val >= 0 && val <= 2) tWindowType = val;
}
[windMatrix selectCellAt:tWindowType :0];
[self changeWindowTypeAndRemember:NO];
return self;
}
- getScreenSaverSetting
{
const char *ptr;
if((evs = NXOpenEventStatus()) == 0)
{ perror("NXOpenEventStatus failed.");
exit(10);
}
[self getDimBrightness:&dimBrightness];
//in case the old dim brightness is somehow invalid, I reset it
if (dimBrightness > .25)
{
dimBrightness = .25;
[self _setDimBrightness:&dimBrightness];
}
[screenSaver setState:0];
ptr = NXGetDefaultValue([NXApp appName], "screenSaver");
if (!ptr || !strcmp(ptr,"Off")) [self setScreenSaver:NO andRemember:NO];
else [self setScreenSaver:YES andRemember:NO];
return self;
}
- changeScreenSaverSetting:sender
{
[self setScreenSaver:([screenSaver state])andRemember:YES];
return self;
}
- setScreenSaver:(BOOL)val andRemember:(BOOL)rem
{
[screenSaver setState:val];
screenSaverVal = val;
if (val)
{
// turn it on...
[self calcDimTime];
if (rem) NXWriteDefault([NXApp appName], "screenSaver", "On");
}
else
{
// turn it off...
if (rem) NXRemoveDefault([NXApp appName], "screenSaver");
}
return self;
}
- calcDimTime
{
double dimTime;
[self getDimTime :&dimTime];
if (dimTime < 0) dimTime = .1;
if (screenSaverVal && !doingSaver)
{
// printf("BackSpace calcDimTime: dims in %f seconds\n",dimTime);
[self perform:@selector(maybeDoScreenSaver:)
with:self
afterDelay:SEC2MS(dimTime)
cancelPrevious:YES];
}
return self;
}
- maybeDoScreenSaver:sender
{
NXEvent anEvent;
BOOL autoDimmed;
// in case timed entry fires but user has killed screen saver
if (!screenSaverVal || doingSaver) return self;
autoDimmed = NXAutoDimState(evs);
if (!autoDimmed)
{
[self calcDimTime];
return self;
}
// The perform:afterDelay: method starts a timed entry to
// invoke maybeDoScreenSaver, so we are in a timed entry
// right now. If we just jumped into doScreenSaver:, we
// would interrupt the doDistributorLoop method while
// it's still focused on the spaceView. By posting an
// event, we force that loop to bail out so we can jump
// into the screen saver cleanly.
keepLooping = NO; // There was a bug related to this at one point.
// I don't think it's necessary anymore.
anEvent.type = NX_APPDEFINED;
anEvent.data.compound.subtype = BSDOSAVER;
anEvent.ctxt = [NXApp context];
DPSPostEvent(&anEvent,0);
return self;
}
- applicationDefined:(NXEvent *)theEvent
{
switch (theEvent->data.compound.subtype)
{
case BSDOSAVER:
[self doScreenSaver:self];
[self calcDimTime]; // reset to fire again
break;
case BSOPENFILE:
[self doDelayedOpenFile];
break;
default:
break;
}
return self;
}
- showFakeScreenSaverAfterPause:sender
{
usleep(250000);
return [self showFakeScreenSaver:sender];
}
- showFakeScreenSaver:sender
{
[self screenSaverMode];
NXSetAutoDimState(evs, YES);
[self doScreenSaver:self];
NXSetAutoDimState(evs, NO);
[self normalMode]; //usually not necessary
// reset to fire again
[self calcDimTime];
return self;
}
- doScreenSaver:sender
{
int oldWindowType;
BOOL mouseOK, oldTimerValid;
BOOL ignoreMouseMovement = NO;
BOOL isHidden;
NXRect trackingRect;
NXPoint mouseLoc;
NXEvent dummyEvent;
BOOL passwordOK;
BOOL stoleActivation = NO;
int oldActiveApp = 0;
// must be sure we don't enter on timed entry after faking saver
doingSaver = YES;
isHidden = [NXApp isHidden];
if (isHidden)
{
[NXApp unhideWithoutActivation:self];
}
if ([password isLocked])
{
oldActiveApp = [NXApp activateSelf:YES];
stoleActivation = YES;
}
[self setVirtualViewIndexAndIncrement:YES];
//save old window state
oldWindowType = [windMatrix selectedRow];
globalTier = SAVERTIER;
[self blackOutAllScreens];
//background window on screen
[windMatrix selectCellAt:BACKWINDOW :0];
[self changeWindowTypeAndRemember:NO];
//nuke timer so timed entry doesn't fire
oldTimerValid = timerValid;
[self removeTimer];
//set background window tier to SAVERTIER
if ([self backingTypeForView:spaceView] == NX_BUFFERED)
{
// make sure the one shot buffer really exists
//[spaceWindow display]; //xxx
if ([spaceWindow windowNum] <= 0) [spaceWindow display];
PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
}
else
{
PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
[spaceView fillBoundsWithBlack];
[spaceView display];
}
NXPing();
[self screenSaverMode];
if ([spaceView respondsTo:@selector(enteredScreenSaverMode)])
[spaceView enteredScreenSaverMode];
do {
//obscure cursor
PShidecursor();
[spaceView lockFocus];
if ([spaceView respondsTo:@selector(didLockFocus)])
[spaceView didLockFocus];
if ([spaceView respondsTo:@selector(ignoreMouseMovement)])
ignoreMouseMovement = [spaceView ignoreMouseMovement];
[spaceWindow getMouseLocation:&mouseLoc];
trackingRect.origin.x = mouseLoc.x - 100;
trackingRect.origin.y = mouseLoc.y - 100;
trackingRect.size.width = trackingRect.size.height = 200;
do {
[spaceView oneStep];
[spaceWindow flushWindow];
NXPing(); // Synchronize postscript for smoother animation
// note: window and view coordinates the same!
// so I don't have to convert to view coord system
if (ignoreMouseMovement) mouseOK = YES;
else
{
[spaceWindow getMouseLocation:&mouseLoc];
mouseOK = [spaceView mouse:&mouseLoc inRect:&trackingRect];
}
[spaceView oneStep];
[spaceWindow flushWindow];
NXPing(); // Synchronize postscript for smoother animation
} while (mouseOK && ([NXApp peekNextEvent:
(NX_MOUSEUPMASK|NX_KEYDOWNMASK)
into:&dummyEvent waitFor:0.0
threshold:NX_BASETHRESHOLD] == NULL));
[spaceView unlockFocus];
//restore cursor
PSshowcursor();
passwordOK = [password checkPassword:
NXLocalString("Screen is locked. Enter password to unlock:",0,0)
randomPos:YES checkLock:YES withView:spaceView];
if (!passwordOK) NXSetAutoDimState(evs, YES);
} while (!passwordOK);
if ([spaceView respondsTo:@selector(willExitScreenSaverMode)])
[spaceView willExitScreenSaverMode];
NXSetAutoDimState(evs, NO);
[self normalMode];
//background window tier to BACKGROUNDTIER
PSsetwindowlevel(BACKGROUNDTIER, [spaceWindow windowNum]);
globalTier = BACKGROUNDTIER;
if (([self backingTypeForView:spaceView] != NX_BUFFERED) &&
oldWindowType == BACKWINDOW)
// this justs fixes a display bug for really lazy nonretained windows
{
[spaceView fillBoundsWithBlack];
[spaceView display];
}
if (oldTimerValid) [self createTimer];
[self unBlackOutAllScreens];
//restore old window state
[windMatrix selectCellAt:oldWindowType :0];
[self changeWindowTypeAndRemember:NO];
if (stoleActivation)
{
if (oldActiveApp) [NXApp activate:oldActiveApp];
else [NXApp deactivateSelf];
}
if (isHidden)
{
[NXApp hide:self];
}
doingSaver = NO;
return self;
}
- appWillTerminate:sender
{
[self normalMode];
return self;
}
- appDidBecomeActive:sender
{
id theMatrix;
theMatrix = [viewSelectionBrowser matrixInColumn:0];
[theMatrix scrollCellToVisible:realViewIndex :0];
return self;
}
- app:sender powerOffIn:(int)ms andSave:(int)aFlag
{
return [NXApp terminate:self];
}
- getPrioritySetting
{
const char *ptr;
int val;
[mySlider setMinValue: 0];
[mySlider setMaxValue: 10];
ptr = NXGetDefaultValue([NXApp appName], "priority");
if (ptr)
{
sscanf(ptr,"%d",&val);
if (val >= 0 && val <= 10) priority = val;
else priority = 4;
}
else priority = 4;
[[mySlider cell] setIntValue:priority];
[[priorityLevel cell] setIntValue:priority];
// use mach call rather than unix - mach lets me increase priority!
// setpriority(PRIO_PROCESS, 0, priority);
cthread_priority(cthread_self(), priority, FALSE);
return self;
}
- changeSliderValue:sender
{
priority = [[mySlider cell] intValue];
[[priorityLevel cell] setIntValue:priority];
return self;
}
- saveSliderValue
{
char str[50];
// setpriority(PRIO_PROCESS, 0, priority);
cthread_priority(cthread_self(), priority, FALSE);
sprintf(str,"%d", priority);
NXWriteDefault([NXApp appName], "priority", str);
return self;
}
- windowWillResize:sender toSize:(NXSize *)frameSize
{
if (frameSize->width < 100) frameSize->width = 100;
if (frameSize->height < 100) frameSize->height = 100;
return self;
}
- windowWillClose:sender
{
[windMatrix selectCellAt:NOWINDOW :0];
[self perform:@selector(changeWindowType:) with:self
afterDelay:1 cancelPrevious:YES];
return nil;
}
BStimeval currentTimeInMs()
{
struct timeval curTime;
gettimeofday (&curTime, NULL);
return (curTime.tv_sec) * 1000 + curTime.tv_usec / 1000;
}
//
// Additional methods to handle a common image object for views.
// Lennart Lovstrad, Rank Xerox EuroPARC, August 1991.
//
- setImageFromFile: (const char *) filename
{
[image free];
image = [[NXImage alloc] initFromFile: filename];
if (image == nil)
{
NXRunAlertPanel([NXApp appName], NXLocalString("Could not open %s",0,0),
NULL, NULL, NULL, filename);
image = nil;
//return nil; //can't return, image is invalid
}
return [self commonImageInit];
}
- setImageFromName: (const char *) name
{
[image free];
image = [[NXImage alloc] initFromSection: name];
return [self commonImageInit];
}
- commonImageInit
{
[imageView setImage: image];
[imageView display];
if ([spaceView respondsTo:@selector(setImage:)])
[spaceView setImage: image];
if ([self backingTypeForView:spaceView] != NX_BUFFERED)
{
[spaceView fillBoundsWithBlack];
[spaceView display];
}
return self;
}
- getImageFile
{
const char *filename;
filename = NXGetDefaultValue([NXApp appName], "imageFile");
if (filename)
[self setImageFromFile: filename];
else [self setImageFromName: "defaultImage"];
return self;
}
- setImageFileFrom: sender
{
id openPanel = [OpenPanel new];
const char *fileTypes[] = {"tiff", "eps", NULL};
if ([openPanel runModalForTypes: fileTypes])
{
[self setImageFromFile: [openPanel filename]];
NXWriteDefault([NXApp appName], "imageFile", [openPanel filename]);
}
[spaceView display]; //don't know why this is necessary...
return self;
}
// This should return a float between 0 and 1
float frandom()
{
float val = (random() & 0x7fffffff);
val /= 0x7fffffff;
return val;
}
float randBetween(float a, float b)
{
float val, scale, t;
if (a > b)
{ t = a; a = b; b = t;
}
scale = (b-a);
val = scale * frandom();
return (a + val);
}
@end